package com.derbysoft.ota.application.translator.rs;

import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.ota.infrastructure.context.RoutingContextHolder;
import com.derbysoft.ota.interfaces.protocol._2009a.CancelPenaltiesType;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelReservationIDsType;
import com.derbysoft.ota.interfaces.protocol._2009a.ResGlobalInfoType;
import com.derbysoft.ota.interfaces.protocol._2009a.TotalType;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelReservationIDsType.HotelReservationID;
import com.derbysoft.remote.dswitch.generic.constants.UniqueIDType;
import com.derbysoft.remote.dswitch.hotel.dto.CancelPolicyDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationIDDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationRS;
import com.derbysoft.remote.dswitch.hotel.dto.TotalDTO;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
import com.googlecode.functionalcollections.FunctionalIterables;

public class ResGlobalInfoTranslator implements
		Translator<Entry<HotelReservationRS, ResGlobalInfoType>, ResGlobalInfoType> {

	public static final String DSWITCH2_SOURCE = "DerbySoftDSwitch2";
	
	private Translator<TotalDTO, TotalType> totalTranslator;
	private Translator<CancelPolicyDTO, CancelPenaltiesType> cancelPenaltiesTranslator;
	
	@Inject
	public ResGlobalInfoTranslator(
		Translator<TotalDTO, TotalType> totalTranslator,
		Translator<CancelPolicyDTO, CancelPenaltiesType> cancelPenaltiesTranslator) {
		this.totalTranslator = totalTranslator;
		this.cancelPenaltiesTranslator = cancelPenaltiesTranslator;
	}

	@Override
	public ResGlobalInfoType translate(Entry<HotelReservationRS, ResGlobalInfoType> source) {
		ResGlobalInfoType dest = (ResGlobalInfoType) source.getValue().clone();
		HotelReservationRS switchRS = source.getKey();
		processReservationIds(switchRS, dest);
		dest.setTotal(total(switchRS.getTotal()));
		dest.setCancelPenalties(cancelPenalties(switchRS));
		return dest;
	}

	private void processReservationIds(
		HotelReservationRS hotelReservationRS,
		ResGlobalInfoType dest) {
		
		if (dest.getHotelReservationIDs() == null) {
			dest.setHotelReservationIDs(new HotelReservationIDsType());
		}
		dest.getHotelReservationIDs().getHotelReservationID().addAll(resReservationIds(hotelReservationRS.getHotelReservationIDs()));
	}

	private Collection<HotelReservationID> resReservationIds(List<HotelReservationIDDTO> hotelReservationIDs) {
		return FunctionalIterables.make(hotelReservationIDs).select(
			new Predicate<HotelReservationIDDTO>() {
				public boolean apply(HotelReservationIDDTO input) {
					return UniqueIDType.HOTEL == input.getResIDType() 
							|| UniqueIDType.ERSP == input.getResIDType();
				}
			}
		).map(
			new Function<HotelReservationIDDTO, HotelReservationID>() {
				public HotelReservationID apply(HotelReservationIDDTO from) {
					return reservationId(from);
				}
			}
		).toCollection();
	}

	private HotelReservationID reservationId(HotelReservationIDDTO from) {
		HotelReservationID hotelReservationID = new HotelReservationID();
		hotelReservationID.setResIDType(from.getResIDType().getCode());
		hotelReservationID.setResIDValue(from.getResIDValue());
		
		if (UniqueIDType.HOTEL == from.getResIDType()) {
			hotelReservationID.setResIDSource(RoutingContextHolder.get().getDestination());
		} else if (UniqueIDType.ERSP == from.getResIDType()) {
			hotelReservationID.setResIDSource(DSWITCH2_SOURCE);
		}
		
		return hotelReservationID;
	}
	
	private TotalType total(TotalDTO totalDTO) {
		return totalTranslator.translate(totalDTO);
	}	

	private CancelPenaltiesType cancelPenalties(HotelReservationRS switchRS) {
		CancelPolicyDTO switchCancelPolicy = switchRS.getCancelPolicy();
		if (switchCancelPolicy == null) {
			return null;
		}
		return cancelPenaltiesTranslator.translate(switchCancelPolicy);
	}
	
}
